/*-------------------------------------------------------------------------
 *
 * wait_error.c
 *		将wait/waitpid(2)结果代码转换为人类可读的字符串
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/common/wait_error.c
 *
 *-------------------------------------------------------------------------
 */

#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif

#include <signal.h>
#include <sys/wait.h>

/*
 * 返回一个人类可读的字符串，解释子进程终止的原因。
 * 参数是由wait(2)或waitpid(2)返回的返回代码。
 * 结果是一个翻译后的、palloc'd或malloc'd字符串。
 */
char * wait_result_to_str(int fc_exitstatus)
{
	char		fc_str[512];

	if (WIFEXITED(fc_exitstatus))
	{
		/*
		 * 为一些在shell中具有特殊含义的常见退出代码提供更具体的错误信息。
		 */
		switch (WEXITSTATUS(fc_exitstatus))
		{
			case 126:
				snprintf(fc_str, sizeof(fc_str), _("command not executable"));
				break;

			case 127:
				snprintf(fc_str, sizeof(fc_str), _("command not found"));
				break;

			default:
				snprintf(fc_str, sizeof(fc_str),
						 _("child process exited with exit code %d"),
						 WEXITSTATUS(fc_exitstatus));
		}
	}
	else if (WIFSIGNALED(fc_exitstatus))
	{
#if defined(WIN32)
		snprintf(str, sizeof(str),
				 _("child process was terminated by exception 0x%X"),
				 WTERMSIG(exitstatus));
#else
		snprintf(fc_str, sizeof(fc_str),
				 _("child process was terminated by signal %d: %s"),
				 WTERMSIG(fc_exitstatus), pg_strsignal(WTERMSIG(fc_exitstatus)));
#endif
	}
	else
		snprintf(fc_str, sizeof(fc_str),
				 _("child process exited with unrecognized status %d"),
				 fc_exitstatus);

	return pstrdup(fc_str);
}

/*
 * 如果wait(2)的结果表明子进程因指定信号而终止，则返回true。
 *
 * 之所以将其作为包装函数包含，是因为有两种情况：
 * 信号可能是由我们的直接子进程接收的，或者在我们和已终止的子进程之间可能有一个shell进程。
 * 根据POSIX，shell会使用退出代码128 + 信号编号报告子进程的死亡。
 *
 * 如果没有中间shell的可能性，则不需要（并且可能不应该）使用此函数。
 */
bool wait_result_is_signal(int fc_exit_status, int fc_signum)
{
	if (WIFSIGNALED(fc_exit_status) && WTERMSIG(fc_exit_status) == fc_signum)
		return true;
	if (WIFEXITED(fc_exit_status) && WEXITSTATUS(fc_exit_status) == 128 + fc_signum)
		return true;
	return false;
}

/*
 * 如果wait(2)的结果表明子进程因任何信号而终止，则返回true。
 * 我们将直接子进程的死亡或shell报告的子进程死亡视为符合条件。
 *
 * 如果include_command_not_found为true， 还会对表示“未找到命令”等的shell退出代码返回true
 * （具体来说，退出代码126和127；见上文）。
 */
bool wait_result_is_any_signal(int fc_exit_status, bool fc_include_command_not_found)
{
	if (WIFSIGNALED(fc_exit_status))
		return true;
	if (WIFEXITED(fc_exit_status) &&
		WEXITSTATUS(fc_exit_status) > (fc_include_command_not_found ? 125 : 128))
		return true;
	return false;
}
